﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using Domain.Core.Extensions;
using System.Data.Objects.DataClasses;
using System.Data;
using System.Reflection;
using Domain.Core;
using Domain.Core.Specification;
using System.Linq.Expressions;
namespace Infrastructure.Core
{
    /// <summary>
    /// EF ORM 操作功能类
    /// 它不是抽象类，它在基础设施层会以基类或者功能对象的方式出现
    /// </summary>
    public class ObjectContextRepository<TEntity> :
      ICompleteRepository<TEntity> where TEntity : class
    {
        protected ObjectContext _db { get; private set; }

        public Domain.Core.ICompleteRepository<TEntity> ICompleteRepository
        {
            get
            {
                throw new System.NotImplementedException();
            }
            set
            {
            }
        }
    
        IUnitOfWork iUnitWork;
        public ObjectContextRepository(IUnitOfWork db)
        {
            iUnitWork = db;
            _db = (ObjectContext)db;
        }


        #region IRepository<T> 成员

        public void Add(TEntity item)
        {
            _db.CreateObjectSet<TEntity>().AddObject(item);
            SaveChanges();
        }


        public void Remove(TEntity item)
        {
            (item as IEntityWithKey).EntityKey = _db.CreateEntityKey(typeof(TEntity).Name, item);
            _db.Attach((item as IEntityWithKey));
            _db.ObjectStateManager.ChangeObjectState(item, EntityState.Deleted);

            SaveChanges();
        }

        public void Modify(TEntity item)
        {
            (item as IEntityWithKey).EntityKey = _db.CreateEntityKey(typeof(TEntity).Name, item);
            _db.Attach((item as IEntityWithKey));
            _db.ObjectStateManager.ChangeObjectState(item, EntityState.Deleted);

            SaveChanges();
        }
        public TEntity GetEntity(ISpecification<TEntity> specification)
        {
            return GetEntities().FirstOrDefault(specification.SatisfiedBy());
        }
        public IQueryable<TEntity> GetEntities()
        {
            return _db.CreateObjectSet<TEntity>();
        }

        public IQueryable<TEntity> GetEntities(ISpecification<TEntity> specification)
        {
            ObjectQuery<TEntity> query = GetEntities() as ObjectQuery<TEntity>; ;
            query.MergeOption = MergeOption.NoTracking;
            return query.Where(specification.SatisfiedBy());
        }

        public IEnumerable<TEntity> GetEntities(
            int pageIndex,
            int pageCount,
            Action<Orderable<TEntity>> order)
        {
            return GetEntities(null, pageIndex, pageCount, order);
        }

        public IEnumerable<TEntity> GetEntities(
            ISpecification<TEntity> specification,
            int pageIndex,
            int pageCount,
            Action<Orderable<TEntity>> order)
        {
            Orderable<TEntity> orderable;
            if (specification == null)
                orderable = new Orderable<TEntity>(GetEntities().AsQueryable());
            else
                orderable = new Orderable<TEntity>(GetEntities(specification).AsQueryable());

            order(orderable);
            return orderable.Queryable
                            .Skip(pageIndex * pageCount)
                            .Take(pageCount);
        }

        public IQueryable<TEntity> GetEntities(Expression<Func<TEntity, bool>> predicate)
        {
            return GetEntities().Where(predicate);
        }
        #endregion

        #region IExtensionRepository<T> 成员

        public void Add(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i => this.Add(i));
        }

        public void Modify(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i => this.Modify(i));
        }

        public void Remove(IEnumerable<TEntity> item)
        {
            item.ToList().ForEach(i => this.Remove(i));
        }

        public TEntity Find(params object[] id)
        {
            var count = 0;
            List<PropertyInfo> res_Primary = new List<PropertyInfo>();
            List<EntityKeyMember> keyMemberList = new List<EntityKeyMember>();
            PropertyInfo[] properties = typeof(TEntity).GetProperties();
            foreach (PropertyInfo pI in properties)
            {
                System.Object[] attributes = pI.GetCustomAttributes(true);
                foreach (object attribute in attributes)
                {
                    if (attribute is EdmScalarPropertyAttribute)
                    {
                        if ((attribute as EdmScalarPropertyAttribute).EntityKeyProperty && !(attribute as EdmScalarPropertyAttribute).IsNullable)
                            keyMemberList.Add(new EntityKeyMember(pI.Name, id[count]));
                        count++;
                    }

                }
            }
            return _db.GetObjectByKey(new EntityKey(_db.DefaultContainerName + "." + typeof(TEntity).Name, keyMemberList)) as TEntity;
        }

        #endregion

        #region Protected Methods
        /// <summary>
        /// 根据工作单元的IsNotSubmit的属性，去判断是否提交到数据库
        /// 一般地，在多个repository类型进行组合时，这个IsNotSubmit都会设为true，即不马上提交，
        /// 而对于单个repository操作来说，它的值不需要设置，使用默认的false，将直接提交到数据库，这也保证了操作的原子性。
        /// </summary>
        protected virtual void SaveChanges()
        {
            if (!iUnitWork.IsNotSubmit)
                iUnitWork.Save();
        }
        #endregion

        #region IRepository<T> 成员


        public void Modify(Expression<Action<TEntity>> entity)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IRepository<TEntity> 成员


        public TEntity GetEntity(Expression<Func<TEntity, bool>> predicate)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
